package com.javaxiaobang.counter.aspect.log;

import com.alibaba.fastjson.JSON;
import com.javaxiaobang.counter.exception.CounterException;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 功    能：日志AOP
 * 作    者：java潇邦
 * 时    间：2018-05-19
 */
@Order
@Aspect
@Component("commonLogCounterAop")
public class LogCounterAop {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private static ExecutorService pool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

    @Autowired
    private LogCounterLocalBusiness logCounterLocalBusiness;
    @Autowired
    private LogCounterRemoteBusiness logCounterRemoteBusiness;

    //切入点
    @Pointcut("@annotation(com.javaxiaobang.counter.aspect.log.LogCounter)")
    public void anyMethod() {
    }

    //方法执行之前
    @Before("anyMethod()")
    public void before(final JoinPoint joinPoint) {
        try {
            Signature signature = joinPoint.getSignature();
            MethodSignature methodSignature = (MethodSignature) signature;
            Method method = methodSignature.getMethod();
            if (method != null && method.isAnnotationPresent(LogCounter.class)) {
                String methodName = method.getName();
                final LogCounter aspect = method.getAnnotation(LogCounter.class);
                if (aspect.useLogFile()) {
                    logger.info("{}{}方法的参数值:{}", aspect.counterName(), methodName, JSON.toJSONString(joinPoint.getArgs()));
                }
                final String counterName = StringUtils.isBlank(aspect.counterName()) ? methodName : aspect.counterName();
                if (aspect.useLocal()) {
                    pool.submit(new Runnable() {
                        @Override
                        public void run() {
                            logCounterLocalBusiness.execute(counterName);
                        }
                    });
                }
                if (aspect.useRemote()) {
                    pool.submit(new Runnable() {
                        @Override
                        public void run() {
                            logCounterRemoteBusiness.execute(counterName);
                        }
                    });
                }
            }
        } catch (Exception e) {
            logger.debug("before切面异常:", e);
        }
    }

    //方法执行之后
    @AfterReturning(pointcut = "anyMethod()", returning = "retVal")
    public void after(JoinPoint joinPoint, Object retVal) {
        try {
            Signature signature = joinPoint.getSignature();
            MethodSignature methodSignature = (MethodSignature) signature;
            Method method = methodSignature.getMethod();
            if (method != null) {
                String methodName = method.getName();
                LogCounter aspect = method.getAnnotation(LogCounter.class);
                if (aspect != null && aspect.useLogFile()) {
                    logger.info("{}{}方法的返回值:{}", aspect.counterName(), methodName, JSON.toJSONString(retVal));
                }
            }
        } catch (Exception e) {
            logger.debug("after切面异常:", e);
        }
    }

    //方法执行之后异常日志
    @AfterThrowing(pointcut = "anyMethod()", throwing = "e")
    public void afterThrowing(JoinPoint joinPoint, Throwable e) throws CounterException {
        //不需要再记录ServiceException，因为在service异常切面中已经记录过
        if (e instanceof CounterException) {
            throw (CounterException) e;
        } else {
            Signature signature = joinPoint.getSignature();
            MethodSignature methodSignature = (MethodSignature) signature;
            Method method = methodSignature.getMethod();
            if (method != null) {
                String methodName = method.getName();
                LogCounter aspect = method.getAnnotation(LogCounter.class);
                logger.warn("{}{}方法异常:", aspect.counterName(), methodName, e);
                throw new CounterException();
            }
        }
    }


}
